DATA SEGMENT
    BUF DB 13,11,248,14,209,45,124,44,73,81,252,40,111,63,228,25,13,177,143,110,192,199,213,51,127,143,106,41,119,81,120,10,69,5,61,212,46,147,118,127,40,161,239,5,214,53,86,58,199,222,
    LEN DW $ - BUF
    ST1 DB 'ORIGIN:', 0DH, 0AH, '$'
    ST2 DB 0DH, 0AH, 'SORTING...', 0DH, 0AH, 0DH, 0AH, '$'
    ST3 DB 'SORTED:', 0DH, 0AH, '$'
    TAB DB 30H, 31H, 32H, 33H, 34H, 35H, 36H, 37H, 38H, 39H, 41H, 42H, 43H, 44H, 45H, 46H   ; hash map
DATA ENDS

STACK SEGMENT STACK
    DW 100 DUP(?)
STACK ENDS

CODE SEGMENT
    ASSUME CS:CODE, DS:DATA, SS:STACK
START:
    MOV AX, DATA
    MOV DS, AX

    MOV  DX, OFFSET ST1
    CALL PTS        ; display ST1
    CALL DSP        ; display BUF
    MOV  DX, OFFSET ST2
    CALL PTS        ; display ST2
    CALL SOT        ; sort    BUF
    MOV  DX, OFFSET ST3
    CALL PTS        ; display ST3
    CALL DSP        ; display BUF

    MOV AH, 4CH     ; OUT
    INT 21H

; @brief: display BUF in hex
; @param: IN BUF: the start of nums
; @param: IN LEN: the number of nums
DSP PROC NEAR
    PUSH AX
    PUSH BX
    PUSH CX
    PUSH DX
    XOR  BX, BX
DO: CALL DSL        ; display 10 nums by order
    MOV  AH , 2
    MOV  DL , 0DH   ; \r
    INT  21H
    MOV  AH , 2
    MOV  DL , 0AH   ; \n
    INT  21H
    ; CX will be 0 if func DSL has display 10 nums
    ; when not enough nums to show, DSL will RET early
    ; so we can end the loop if CX != 0
    CMP  CX, 0
    JE   DO
    POP  DX
    POP  CX
    POP  BX
    POP  AX
    RET
DSP ENDP

; @brief: display 10 nums in hex in one line
; @param: IN     BUF: the start of nums
; @param: IN     LEN: the number of nums
; @param: IN&OUT BX:  the offset from BUF
; @param: OUT    CX:  end flag
DSL PROC NEAR
    PUSH AX
    PUSH DX
    MOV  CX, 10
DI: CALL DSB        ; display a byte BUF[BX]
    MOV  AH , 2
    MOV  DL , 48H   ; H
    INT  21H
    MOV  AH , 2
    MOV  DL , 00H   ; space
    INT  21H
    INC  BX
    CMP  BX, WORD PTR LEN
    JAE  RT
    LOOP DI
RT: POP  DX
    POP  AX
    RET
DSL ENDP

; @brief: display a byte in hex
; @param: IN     BUF: the start of nums
; @param: IN     LEN: the number of nums
; @param: IN&OUT BX:  the offset from BUF
DSB PROC NEAR
    PUSH AX
    PUSH CX
    PUSH DX
    PUSH SI
    XOR  DX, DX
    MOV  AH, 2
    MOV  DL, BUF[BX]
    MOV  CL, 4
    SHR  DL, CL     ; display high 4
    MOV  SI, DX
    MOV  DL, TAB[SI]
    INT  21H
    XOR  DX, DX
    MOV  AH, 2
    MOV  DL, BUF[BX]
    AND  DL, 0FH    ; display low  4
    MOV  SI, DX
    MOV  DL, TAB[SI]
    INT  21H
    POP  SI
    POP  DX
    POP  CX
    POP  AX
    RET
DSB ENDP

; @brief: sort BUF with insert sort
; @princip: BX = 0
;           sort BUF[0]...BUF[BX]
;           INC  BX
;           do   sort until BX==LEN
; @param: IN&OUT BUF: the start of nums
; @param: IN     LEN: the number of nums
SOT PROC NEAR
    PUSH AX
    PUSH BX
    PUSH CX
    PUSH DX
    XOR  BX, BX
SO: INC  BX
    CMP  BX, LEN
    JAE  SR
    MOV  SI, BX
    S2: MOV  AL, BUF[SI-1]
    CMP  AL, BUF[SI]
    JBE  SO
    XCHG AL, BUF[SI]
    XCHG AL, BUF[SI-1]
    DEC  SI
    JMP  S2
SR: POP  DX
    POP  CX
    POP  BX
    POP  AX
    RET
SOT ENDP

; @brief: display string
; @param: IN DX: the offset of string in DATA
PTS PROC NEAR
    PUSH AX
    MOV  AH, 09H
    INT  21H
    POP  AX
    RET
PTS ENDP

CODE ENDS
END START
